package virtualstock.request;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.ejb.EJBException;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.sun.enterprise.admin.util.Debug;

import virtualstock.entity.Game;
import virtualstock.entity.Player;
import virtualstock.exception.GameNotFoundException;
import virtualstock.exception.InvalidParameterException;
import virtualstock.exception.PlayerNotFoundException;
import virtualstock.util.GameDetails;

/**
 * Session Bean implementation class GameControllerBean
 */
@Stateful
public class GameControllerBean implements GameController {
	@PersistenceContext
    private EntityManager em;
    private String gameID;

    /**
     * Default constructor. 
     */
    public GameControllerBean() {
        // TODO Auto-generated constructor stub
    }

	@Override
	public void addPlayerToGame(Long playerID, Long gameID)
		throws InvalidParameterException, PlayerNotFoundException, GameNotFoundException {
		// adds a player to the game
		Player player = null;
		Game game = null;
		
		if (playerID == null) {
			throw new InvalidParameterException("null playerID");
		}
		else if (gameID == null) {
			throw new InvalidParameterException("null gameID");
		}
		
		try {
			game = em.find(Game.class, gameID);
			
			if (gameID == null) {
				throw new GameNotFoundException();
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		
		try {
			player = em.find(Player.class, playerID);
			
			if (player == null) {
				throw new PlayerNotFoundException();
			}
			else {
				game.addPlayer(player);
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
	}

	@Override
	public void addStockToGame(Long stockID, Long gameID) {
		// TODO Auto-generated method stub
		
	}
/*
	@Override
	public Long createNewGame(GameDetails details, Long playerID)
		throws PlayerNotFoundException, InvalidParameterException {
		// makes a new game and enters it into db
		Game game = null;
		Player player = null;
		
		// may be add more checks for the inputs
		if (playerID == null) {
			throw new InvalidParameterException("null playerID");
		}
		
		try {
			player = em.find(Player.class, playerID);
			
			if (player == null) {
				throw new PlayerNotFoundException();
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		
		try {
			game = new Game(
					details.getGameName(),
					details.getCreator(),
					details.getMaxPlayer(),
					details.getInitialBalance(),
					details.getStartDate());
			em.persist(game);
			game.addPlayer(player);
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		
		return game.getGameID();
	}
*/	
	@Override
	public Long createNewGame(GameDetails details)
		throws PlayerNotFoundException, InvalidParameterException {
		// makes a new game and enters it into db
		Game game = null;
		Player player = null;
		
		Debug.print("GameControllerBean create new game");
		// may be add more checks for the inputs
		try {
			player = em.find(Player.class, details.getCreator());
			
			if (player == null) {
				throw new PlayerNotFoundException();
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		try {
			game = new Game(
					details.getGameName(),
					details.getCreator(),
					details.getMaxPlayer(),
					details.getInitialBalance(),
					details.getStartDate());
			em.persist(game);
			game.addPlayer(player);
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		
		return game.getGameID();
	}

	@Override
	public GameDetails getGameDetails(Long gameID)
		throws InvalidParameterException, GameNotFoundException {
		
		// !!! don't use this until portfolio is created
		// because getPlayerIDs is not done.
		
		GameDetails details = null;
		Game game = null;
		
		if (gameID == null) {
			throw new InvalidParameterException("null gameID");
		}
		
		try {
			game = em.find(Game.class, gameID);
			
			if (game == null) {
				System.err.println("GameControllerBean.getGameDetails: Game not found.");
				throw new GameNotFoundException(gameID);
			}
			else {
				details = new GameDetails(
						gameID,
						game.getGameName(),
						game.getCreator(),
						game.getMaxPlayer(),
						game.getInitialBalance(),
						game.getStartDate());
				// currently, not using the following two lines
				List<Long> playerIDs = this.getPlayerIDs(gameID);
				details.setPlayerIDs(playerIDs);
			}
		} catch (Exception ex) {
			System.err.println("GameControllerBean.getGameDetails: Caught an exception.");
			ex.getStackTrace();
		}
		
		return details;
	}

	@Override
	public List<GameDetails> getGamesOfPlayer(Long playerID)
		throws InvalidParameterException, PlayerNotFoundException {
		// returns a List of GameDetails
		
		Collection<Game> games = null;
		Player player = null;
		
		if (playerID == null) {
			throw new InvalidParameterException("null playerID");
		}
		
		try {
//			System.out.println("111111111111111");
			player = em.find(Player.class, playerID);
			em.refresh(player);
//			System.out.println("222222222222222222222");
			if (player == null) {
				throw new PlayerNotFoundException();
			}
			else {
				games = player.getGames();
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		
		return copyGamesToDetails(games);
	}

	@Override
	public List<Long> getStockIDs(Long gameID) {
		// TODO !!! wait until stock is created
		return null;
	}

	@Override
	public void removeGame(Long gameID)
		throws InvalidParameterException, GameNotFoundException {
		// removes game
		Game game = null;
		
		if (gameID == null) {
			throw new InvalidParameterException("null gameID");
		}
		
		try {
			game = em.find(Game.class, gameID);
			
			if (game == null) {
				throw new GameNotFoundException();
			}
			else {
				em.remove(game);
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
	}

	@Override
	public void removePlayerFromGame(Long playerID, Long gameID)
		throws InvalidParameterException, PlayerNotFoundException, GameNotFoundException {
		// removes a player from this game, but the player is not removed from the db
		
		Game game = null;
		Player player = null;
		
		if (playerID == null) {
			throw new InvalidParameterException("null playerID");
		}
		else if (gameID == null) {
			throw new InvalidParameterException("null gameID");
		}
		
		try {
			game = em.find(Game.class, gameID);
			
			if (game == null) {
				throw new GameNotFoundException();
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		
		try {
			player = em.find(Player.class, playerID);
			
			if (player == null) {
				throw new PlayerNotFoundException();
			}
			else {
				game.removePlayer(player);
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
	}

	@Override
	public void removeStockFromGame(Long stockID, Long gameID) {
		// TODO !!! wait until stock is created
		
	}

	@Override
	public List<Long> getPlayerIDs(Long gameID)
		throws InvalidParameterException, GameNotFoundException {
		// !!! don't use this until portfolio is created
		List<Player> players = null;
		
		if (gameID == null) {
			throw new InvalidParameterException("null gameID");
		}
		
		try {
			// this can use portfolio
			players = em.createNamedQuery("Player.FindAllPlayersOfGame").setParameter("gameID", gameID).getResultList();
			
			if (players == null) {
				throw new GameNotFoundException();
			}
		} catch (Exception ex) {
			throw new EJBException(ex);
		}
		
		return copyGameIDsToList(players);
	}
	
	@Override
	public List<GameDetails> getAllAvailableGames(){
		Collection games = null;
		try{
			games = (List<GameDetails>)em.createNamedQuery("Game.GetAllAvailableGame").getResultList();
		}catch (Exception ex) {
			throw new EJBException(ex.getMessage());
		}
		
		if(games.isEmpty())
			return null;
		else
			return copyGamesToDetails(games);
	}
	
	private List<Long> copyGameIDsToList(List<Player> players) {
		List<Long> playerIDList = new ArrayList<Long>();
		Iterator<Player> i = players.iterator();
		
		while (i.hasNext()) {
			Player player = i.next();
			playerIDList.add(player.getPlayerID());
		}
		
		return playerIDList;
	}
	
	
	
	private List<GameDetails> copyGamesToDetails(Collection<Game> games) {
		List<GameDetails> detailsList = new ArrayList<GameDetails>();
		Iterator<Game> i = games.iterator();
		
		while (i.hasNext()) {
			Game game = i.next();
			GameDetails details = new GameDetails(
					game.getGameID(),
					game.getGameName(),
					game.getCreator(),
					game.getMaxPlayer(),
					game.getInitialBalance(),
					game.getStartDate());
			detailsList.add(details);
		}
		
		return detailsList;
	}



}
